From dbe5058b86a2e9974b80045ab4b02a4c78e560da Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Thu, 19 Feb 2015 00:54:14 +0100 Subject: [PATCH] cssnode: Add API to query the timestamp ... and pass it to the API that computes new styles. A special timestamp of 0 means "please don't animate" and is used when no frame clock is available for a node. --- gtk/gtkcssnode.c | 67 +++++++++++++++++++++++++++++++++++++--- gtk/gtkcssnodeprivate.h | 6 ++++ gtk/gtkcsstypes.c | 2 -- gtk/gtkcsstypesprivate.h | 5 +-- gtk/gtkcsswidgetnode.c | 36 ++++++++++++++++++--- gtk/gtkwidget.c | 4 +++ 6 files changed, 106 insertions(+), 14 deletions(-) diff --git a/gtk/gtkcssnode.c b/gtk/gtkcssnode.c index 93d5395cc8..3de1b6ff03 100644 --- a/gtk/gtkcssnode.c +++ b/gtk/gtkcssnode.c @@ -226,6 +226,7 @@ gtk_css_style_needs_recreation (GtkCssStyle *style, static GtkCssStyle * gtk_css_node_real_update_style (GtkCssNode *cssnode, GtkCssChange pending_change, + gint64 timestamp, GtkCssStyle *old_style) { if (!gtk_css_style_needs_recreation (old_style, pending_change)) @@ -285,6 +286,12 @@ gtk_css_node_real_get_style_provider (GtkCssNode *cssnode) return NULL; } +static GdkFrameClock * +gtk_css_node_real_get_frame_clock (GtkCssNode *cssnode) +{ + return NULL; +} + static void gtk_css_node_class_init (GtkCssNodeClass *klass) { @@ -302,6 +309,7 @@ gtk_css_node_class_init (GtkCssNodeClass *klass) klass->create_widget_path = gtk_css_node_real_create_widget_path; klass->get_widget_path = gtk_css_node_real_get_widget_path; klass->get_style_provider = gtk_css_node_real_get_style_provider; + klass->get_frame_clock = gtk_css_node_real_get_frame_clock; } static void @@ -314,6 +322,27 @@ gtk_css_node_init (GtkCssNode *cssnode) cssnode->visible = TRUE; } +static GdkFrameClock * +gtk_css_node_get_frame_clock_or_null (GtkCssNode *cssnode) +{ + while (cssnode->parent) + cssnode = cssnode->parent; + + return GTK_CSS_NODE_GET_CLASS (cssnode)->get_frame_clock (cssnode); +} + +static gint64 +gtk_css_node_get_timestamp (GtkCssNode *cssnode) +{ + GdkFrameClock *frameclock; + + frameclock = gtk_css_node_get_frame_clock_or_null (cssnode); + if (frameclock == NULL) + return 0; + + return gdk_frame_clock_get_frame_time (frameclock); +} + static void gtk_css_node_parent_was_unset (GtkCssNode *node) { @@ -440,6 +469,7 @@ gtk_css_node_reposition (GtkCssNode *node, if (gtk_css_node_get_style_provider_or_null (node) == NULL) gtk_css_node_invalidate_style_provider (node); + gtk_css_node_invalidate (node, GTK_CSS_CHANGE_TIMESTAMP | GTK_CSS_CHANGE_ANIMATIONS); } if (parent) @@ -560,22 +590,30 @@ gtk_css_node_propagate_pending_changes (GtkCssNode *cssnode, } } +static gboolean +gtk_css_node_needs_new_style (GtkCssNode *cssnode) +{ + return cssnode->style_is_invalid; +} + static void -gtk_css_node_ensure_style (GtkCssNode *cssnode) +gtk_css_node_ensure_style (GtkCssNode *cssnode, + gint64 current_time) { GtkCssStyle *new_style; - if (!cssnode->style_is_invalid) + if (!gtk_css_node_needs_new_style (cssnode)) return; if (cssnode->parent) - gtk_css_node_ensure_style (cssnode->parent); + gtk_css_node_ensure_style (cssnode->parent, current_time); if (cssnode->previous_sibling) - gtk_css_node_ensure_style (cssnode->previous_sibling); + gtk_css_node_ensure_style (cssnode->previous_sibling, current_time); new_style = GTK_CSS_NODE_GET_CLASS (cssnode)->update_style (cssnode, cssnode->pending_changes, + current_time, cssnode->style); gtk_css_node_propagate_pending_changes (cssnode, new_style != NULL); @@ -593,7 +631,12 @@ gtk_css_node_ensure_style (GtkCssNode *cssnode) GtkCssStyle * gtk_css_node_get_style (GtkCssNode *cssnode) { - gtk_css_node_ensure_style (cssnode); + if (gtk_css_node_needs_new_style (cssnode)) + { + gint64 timestamp = gtk_css_node_get_timestamp (cssnode); + + gtk_css_node_ensure_style (cssnode, timestamp); + } return cssnode->style; } @@ -755,6 +798,20 @@ gtk_css_node_invalidate_style_provider (GtkCssNode *cssnode) } } +void +gtk_css_node_invalidate_frame_clock (GtkCssNode *cssnode, + gboolean just_timestamp) +{ + /* frame clock is handled by the top level */ + if (cssnode->parent) + return; + + if (just_timestamp) + gtk_css_node_invalidate (cssnode, GTK_CSS_CHANGE_TIMESTAMP); + else + gtk_css_node_invalidate (cssnode, GTK_CSS_CHANGE_TIMESTAMP | GTK_CSS_CHANGE_ANIMATIONS); +} + void gtk_css_node_invalidate (GtkCssNode *cssnode, GtkCssChange change) diff --git a/gtk/gtkcssnodeprivate.h b/gtk/gtkcssnodeprivate.h index 944e01fa21..4101037edb 100644 --- a/gtk/gtkcssnodeprivate.h +++ b/gtk/gtkcssnodeprivate.h @@ -70,8 +70,11 @@ struct _GtkCssNodeClass const GtkWidgetPath * (* get_widget_path) (GtkCssNode *cssnode); /* get style provider to use or NULL to use parent's */ GtkStyleProviderPrivate *(* get_style_provider) (GtkCssNode *cssnode); + /* get frame clock or NULL (only relevant for root node) */ + GdkFrameClock * (* get_frame_clock) (GtkCssNode *cssnode); GtkCssStyle * (* update_style) (GtkCssNode *cssnode, GtkCssChange pending_changes, + gint64 timestamp, GtkCssStyle *old_style); void (* invalidate) (GtkCssNode *node); void (* queue_validate) (GtkCssNode *node); @@ -140,6 +143,9 @@ GtkCssStyle * gtk_css_node_create_style (GtkCssNode * void gtk_css_node_invalidate_style_provider (GtkCssNode *cssnode); +void gtk_css_node_invalidate_frame_clock + (GtkCssNode *cssnode, + gboolean just_timestamp); void gtk_css_node_invalidate (GtkCssNode *cssnode, GtkCssChange change); void gtk_css_node_validate (GtkCssNode *cssnode, diff --git a/gtk/gtkcsstypes.c b/gtk/gtkcsstypes.c index 46e7c1c265..6ab3bc5063 100644 --- a/gtk/gtkcsstypes.c +++ b/gtk/gtkcsstypes.c @@ -57,7 +57,6 @@ _gtk_css_change_for_sibling (GtkCssChange match) { GTK_CSS_CHANGE_POSITION, GTK_CSS_CHANGE_SIBLING_POSITION }, { GTK_CSS_CHANGE_STATE, GTK_CSS_CHANGE_SIBLING_STATE }, { GTK_CSS_CHANGE_SOURCE, 0 }, - { GTK_CSS_CHANGE_ANIMATE, 0 }, { GTK_CSS_CHANGE_PARENT_STYLE, 0 } }; @@ -77,7 +76,6 @@ _gtk_css_change_for_child (GtkCssChange match) { GTK_CSS_CHANGE_SIBLING_POSITION, GTK_CSS_CHANGE_PARENT_SIBLING_POSITION }, { GTK_CSS_CHANGE_SIBLING_STATE, GTK_CSS_CHANGE_PARENT_SIBLING_STATE }, { GTK_CSS_CHANGE_SOURCE, 0 }, - { GTK_CSS_CHANGE_ANIMATE, 0 }, { GTK_CSS_CHANGE_PARENT_STYLE, 0 } }; diff --git a/gtk/gtkcsstypesprivate.h b/gtk/gtkcsstypesprivate.h index d2cd6d3f8e..1f68e9c39a 100644 --- a/gtk/gtkcsstypesprivate.h +++ b/gtk/gtkcsstypesprivate.h @@ -51,8 +51,9 @@ typedef enum { /*< skip >*/ GTK_CSS_CHANGE_PARENT_SIBLING_STATE = (1 << 15), /* add more */ GTK_CSS_CHANGE_SOURCE = (1 << 16), - GTK_CSS_CHANGE_ANIMATE = (1 << 17), - GTK_CSS_CHANGE_PARENT_STYLE = (1 << 18), + GTK_CSS_CHANGE_PARENT_STYLE = (1 << 17), + GTK_CSS_CHANGE_TIMESTAMP = (1 << 18), + GTK_CSS_CHANGE_ANIMATIONS = (1 << 19), GTK_CSS_CHANGE_RESERVED_BIT = (1 << 31) /* Used internally in gtkcssselector.c */ } GtkCssChange; diff --git a/gtk/gtkcsswidgetnode.c b/gtk/gtkcsswidgetnode.c index d3ec5a2043..1bc21244df 100644 --- a/gtk/gtkcsswidgetnode.c +++ b/gtk/gtkcsswidgetnode.c @@ -36,14 +36,28 @@ G_DEFINE_TYPE (GtkCssWidgetNode, gtk_css_widget_node, GTK_TYPE_CSS_NODE) static GtkCssStyle * gtk_css_widget_node_update_style (GtkCssNode *cssnode, GtkCssChange pending_change, + gint64 timestamp, GtkCssStyle *old_style) { if (old_style == NULL) - return GTK_CSS_NODE_CLASS (gtk_css_widget_node_parent_class)->update_style (cssnode, pending_change, old_style); + return GTK_CSS_NODE_CLASS (gtk_css_widget_node_parent_class)->update_style (cssnode, pending_change, timestamp, old_style); return NULL; } +static gboolean +gtk_css_widget_node_queue_callback (GtkWidget *widget, + GdkFrameClock *frame_clock, + gpointer user_data) +{ + GtkCssNode *node = user_data; + + gtk_css_node_invalidate_frame_clock (node, TRUE); + _gtk_container_queue_restyle (GTK_CONTAINER (widget)); + + return G_SOURCE_CONTINUE; +} + static void gtk_css_widget_node_queue_validate (GtkCssNode *node) { @@ -52,8 +66,8 @@ gtk_css_widget_node_queue_validate (GtkCssNode *node) G_GNUC_BEGIN_IGNORE_DEPRECATIONS if (GTK_IS_RESIZE_CONTAINER (widget_node->widget)) widget_node->validate_cb_id = gtk_widget_add_tick_callback (widget_node->widget, - (GtkTickCallback) _gtk_container_queue_restyle, - NULL, + gtk_css_widget_node_queue_callback, + node, NULL); G_GNUC_END_IGNORE_DEPRECATIONS } @@ -128,7 +142,7 @@ gtk_css_widget_node_validate (GtkCssNode *node, new_static_style = validate_static_style (node, static_style, change); - if (new_static_style != static_style) + if (new_static_style != static_style || (change & GTK_CSS_CHANGE_ANIMATIONS)) { GtkCssNode *parent = gtk_css_node_get_parent (node); new_style = gtk_css_animated_style_new (new_static_style, @@ -139,7 +153,7 @@ gtk_css_widget_node_validate (GtkCssNode *node, g_object_unref (new_static_style); } - else if (GTK_IS_CSS_ANIMATED_STYLE (style)) + else if (GTK_IS_CSS_ANIMATED_STYLE (style) && (change & GTK_CSS_CHANGE_TIMESTAMP)) { new_style = gtk_css_animated_style_new_advance (GTK_CSS_ANIMATED_STYLE (style), static_style, @@ -264,6 +278,17 @@ gtk_css_widget_node_get_style_provider (GtkCssNode *node) return gtk_style_context_get_style_provider (gtk_widget_get_style_context (widget_node->widget)); } +static GdkFrameClock * +gtk_css_widget_node_get_frame_clock (GtkCssNode *node) +{ + GtkCssWidgetNode *widget_node = GTK_CSS_WIDGET_NODE (node); + + if (widget_node->widget == NULL) + return NULL; + + return gtk_widget_get_frame_clock (widget_node->widget); +} + static void gtk_css_widget_node_class_init (GtkCssWidgetNodeClass *klass) { @@ -277,6 +302,7 @@ gtk_css_widget_node_class_init (GtkCssWidgetNodeClass *klass) node_class->create_widget_path = gtk_css_widget_node_create_widget_path; node_class->get_widget_path = gtk_css_widget_node_get_widget_path; node_class->get_style_provider = gtk_css_widget_node_get_style_provider; + node_class->get_frame_clock = gtk_css_widget_node_get_frame_clock; } static void diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index cfb4223bfa..b28ebcfba7 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -5446,6 +5446,8 @@ gtk_widget_connect_frame_clock (GtkWidget *widget, gdk_frame_clock_begin_updating (frame_clock); } + gtk_css_node_invalidate_frame_clock (priv->cssnode, FALSE); + if (priv->context) gtk_style_context_set_frame_clock (priv->context, frame_clock); } @@ -5459,6 +5461,8 @@ gtk_widget_disconnect_frame_clock (GtkWidget *widget, if (GTK_IS_CONTAINER (widget)) _gtk_container_stop_idle_sizer (GTK_CONTAINER (widget)); + gtk_css_node_invalidate_frame_clock (priv->cssnode, FALSE); + if (priv->clock_tick_id) { g_signal_handler_disconnect (frame_clock, priv->clock_tick_id); -- 2.30.2